<template>
  <div class="yun-preview">
    <iframe ref="showview" :srcdoc="srcdoc"  sandbox="allow-modals allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts"
      scrolling="yes"
      frameborder="0"
      style="width: 100%;height: 100%;border: none;"></iframe>
  </div>
</template>
<script setup>
import {ref,watch} from "vue"
import { ElMessage } from 'element-plus'
import * as compiler from "@vue/compiler-sfc";
import * as Babel from "@babel/standalone";
import * as sass from 'sass'
const props = defineProps({
  codeType:String,
  code:String
})
const showview = ref(null)
const srcdoc = ref('')
//处理vue模板语法
const  setCodeView=()=>{
  if(props.codeType=='html'){
    srcdoc.value = props.code
  }else{
    const iframe = showview.value
    const iframeDocument = iframe.contentWindow.document;
    let htmlview = `
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <script src='https://cdn.jsdelivr.net/npm/vue@2.6.11'><\/script>
      </head>
      <body id='body'>
        <div id='views'></div>
      </body>
    </html>`
    iframeDocument.open();
    iframeDocument.write(htmlview);
    iframeDocument.close();
    iframe.onload = () => {
      vueToHtml()
    }; 
  }
}
// vue代码转译渲染
const vueToHtml = ()=>{
  const ans = compiler.parse(props.code, {sourceMap:false});
    let { template, script, styles } = ans.descriptor;
    if (!template && !script) return;
    // 处理 template
    template = template ? JSON.stringify(template.content) : '""';
    // 处理 js
    script = script && script.content.trim()
                ? script.content.trim()
                : "export default {}";
    // 转码
    try {
      script = Babel.transform(script, {
        presets: ["es2015"]
      }).code;
    } catch (error) {
      console.log(error)
    }
    const cssStyle = []
    for (let style of styles) {
        const result = sass.compileString(style.content);
        console.log(result.css)
        cssStyle.push(result.css)
    }
   
    const iframeDocument = showview.value.contentWindow.document;
    const fragment = iframeDocument.createDocumentFragment();
    const elBox = iframeDocument.getElementById("views");
    console.log(iframeDocument,fragment)
    // 创建样式
    const newStyle = iframeDocument.createElement("style");
    newStyle.type = "text/css";
    newStyle.innerHTML = cssStyle.join("\n");

    // 创建元素
    const elApp = iframeDocument.createElement("div");
    elApp.setAttribute("id", "app");
    script = getScript(script, template);

    // 创建js
    const newScript = iframeDocument.createElement("script");
    newScript.type = "text/javascript";
    newScript.innerHTML = script;
    if(elBox){
      elBox.innerHTML=""
      // 填充元素
      fragment.appendChild(newStyle);
      fragment.appendChild(elApp);
      fragment.appendChild(newScript);
    
    
      elBox.appendChild(fragment)
    }
   
}
const getScript = (script, template)=>{
      return ` try {
          var exports = {};
          ${script}
          var component = exports.default;
          // 如果定义了 template函数, 则无需 template
          component.template = component.template || ${template}
        } catch (error){
          errorHandler(error)
        }

        new Vue(component).$mount('#app')
      `;
    }
watch(()=>props.code,()=>{
  setCodeView()
})
defineExpose({
  setCodeView
})
</script>
<style lang="scss" scoped>
.yun-preview{
  height:100%;
  background: #fff;
  border:1px solid #f0efef;
}
</style>